﻿using Algorithm_api.calculate.Binomial;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Algorithm_api.calculate.Binomial
{
    public class Binomial
    {
        public int k { get; set; }
        public int n { get; set; }
        public int[,] m { get; set; }

        public Binomial(int k,int n)
        {
            this.k = k;     
            this.n = n;
            m = new int[k + 1,n + 1];
        }

        public BinomialResult getBinomial()
        {
            BinomialResult result = new BinomialResult();
            TimeSpan start = new TimeSpan(DateTime.Now.Ticks);
            result.result_rec = getBinomial(k, n);
            result.time_rec =  start.Subtract(new TimeSpan(DateTime.Now.Ticks)).Duration().TotalMilliseconds.ToString();

            start = new TimeSpan(DateTime.Now.Ticks);
            result.result_mem = getBinomial_m(k, n);
            result.time_mem = start.Subtract(new TimeSpan(DateTime.Now.Ticks)).Duration().TotalMilliseconds.ToString();

            start = new TimeSpan(DateTime.Now.Ticks);
            result.result_iter = getBinomial_r(k, n);
            result.time_iter = start.Subtract(new TimeSpan(DateTime.Now.Ticks)).Duration().TotalMilliseconds.ToString();

            return result;
        }
        

        public int getBinomial(int k, int n)
        {
            if (k == 0 || k == n) return 1;
            else return getBinomial(k - 1, n - 1) + getBinomial(k, n - 1);
        }

        public int getBinomial_m(int k, int n)
        {
            int value;
            if (k == 0 || n == k) value = 1;
            else if (m[k,n] != 0) value = m[k,n];
            else
            {
                m[k,n] = getBinomial_m(k - 1, n - 1) + getBinomial_m(k, n - 1);
                value = m[k, n];
            }
            return value;
        }

        public long getBinomial_r(int k, int n)
        {
            long a = A(k, n);
            int factorial = 1;
            for(int i = 1; i <= k; i++)
            {
                factorial = factorial * i;
            }
            long result = a / factorial;
            return result;
        }
        
        public long A(int x,int y)
        {
            if (y < 0 || x < 0 || x > y) return -1;
            if (x == 1) return y;
            long result = 1;
            for(int i = 0; i< x; i++)
            {
                result = result * (y - i);
            }
            return result;
        }
    }
}
